home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Die Speccy' 97
/
Die Speccy' 97.iso
/
amiga_system
/
the_aminet
/
util
/
libs
/
halt.lzh
/
halt
/
shutdown.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-06
|
11KB
|
439 lines
/*
shutdown.c --- shutdown frontend.
(c) Copyright 1995 SHW Wabnitz
Written by Bernhard Fastenrath (fasten@shw.com)
This file may be distributed under the terms
of the GNU General Public License.
*/
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#if defined (__GNUC__)
#include "halt_inline.h"
#else
#include "halt_pragmas.h"
#endif
#include "halt.h"
int GoDown (int now);
#define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
struct IntuitionBase *IntuitionBase = NULL;
struct Library *HaltBase = NULL;
ShutdownMessage *Smsg = NULL;
ShutdownContext SContext;
struct timerequest *TimerReq = NULL;
struct MsgPort *TimerPort = NULL;
struct MsgPort *ReplyPort = NULL;
struct MsgPort *ShutdownPort = NULL;
ULONG TimerMask;
ULONG TimerErr = 1;
ULONG ShutdownMask;
ULONG ReplyMask;
ULONG WaitMask;
int point_of_no_return = 0;
int ExpectTimeout = 0;
char *ShutdownPortname = "Shutdown";
int SpNameLen;
ULONG ShutdownFlags;
ULONG BroadcastTimeout = 5;
char *CantAllocatePort = "Can't allocate message port.\n";
char *ShutdownCancelled = "shutdown cancelled.\n";
char *OutOfMemory = "Out of memory.\n";
char *SorryTooLate = "Too late to stop shutdown.\n";
int MessageTimedOut = 0;
int HaltFlag = 1, SyncTime = 5;
int FastBoot = 0;
int Error;
char *optarg = NULL;
int
getopt (int argc, char *argv[], char *opts)
{
static int pos = 0;
char *c;
while (++pos < argc && argv[pos][0] != '-');
if (pos >= argc)
return -1;
if ((c = strchr (opts, (int) argv[pos][1])) == 0)
return (int) '?';
if (*(c+1) != ':')
return (int) *c;
if (strlen (argv[pos]) > 2)
optarg = argv[pos] + 2;
else if (pos+1 < argc)
optarg = argv[pos+1];
else
return (int) '?';
return (int) *c;
}
ShutdownMessage *
AllocShutdownMessage ()
{
ShutdownNode *node;
if (!(node = (ShutdownNode *)
AllocMem (sizeof (ShutdownNode), MEMF_PUBLIC | MEMF_CLEAR)))
{
return NULL;
}
node -> sn_Msg.sm_Msg.mn_ReplyPort = ReplyPort;
node -> sn_Msg.sm_Msg.mn_Length = sizeof (ShutdownMessage);
node -> sn_Msg.sm_Context = &SContext;
AddTail (&SContext.sc_List, (struct Node *) node);
return &node -> sn_Msg;
}
ULONG
PutAndGet (ShutdownMessage *smsg, char *portname)
{
struct MsgPort *prt;
Forbid ();
if (prt = FindPort (portname))
{
PutMsg (prt, (struct Message *) smsg);
Permit ();
do
WaitPort (ReplyPort);
while (!GetMsg (ReplyPort));
}
else
Permit ();
return ((ULONG) prt);
}
void
CleanUp (char *error)
{
ShutdownNode *node, *next;
if (error)
printf (error);
if (!TimerErr)
CloseDevice ((struct IORequest *) TimerReq);
if (TimerReq)
DeleteIORequest (TimerReq);
if (TimerPort)
DeleteMsgPort (TimerPort);
if (ReplyPort)
DeleteMsgPort (ReplyPort);
if (ShutdownPort)
{
if (ShutdownPort -> mp_Node.ln_Name)
FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
RemPort (ShutdownPort);
DeleteMsgPort (ShutdownPort);
}
node = (ShutdownNode *) SContext.sc_List.lh_Head;
while (next = (ShutdownNode *) node -> sn_MinNode.mln_Succ)
{
FreeMem (node, sizeof (ShutdownNode));
node = next;
}
if (HaltBase)
CloseLibrary (HaltBase);
if (IntuitionBase)
CloseLibrary ((struct Library *) IntuitionBase);
exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
int
CancelShutdown (void)
{
if (point_of_no_return)
return 0;
if (SContext.sc_TimeOuts)
{
printf ("Shutdown cannot exit, there are still %d unreplied messages.\n",
SContext.sc_TimeOuts);
return 0;
}
if (ExpectTimeout == 1)
{
printf ("Press CTRL-C to abort the following "
"cancel message before it times out.\n");
ExpectTimeout = 2;
}
if (Smsg)
{
BroadcastTimeout = 0;
Smsg -> sm_Status = SHUTDOWN_ABORT;
BroadcastShutdownMsg ();
}
CleanUp (ShutdownCancelled);
}
int
BroadcastShutdownMsg ()
{
if (BroadcastTimeout)
{
TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
TimerReq -> tr_time.tv_secs = BroadcastTimeout;
TimerReq -> tr_time.tv_micro = 0;
SendIO ((struct IORequest *) TimerReq);
}
Smsg -> sm_Flags = ShutdownFlags;
ShutdownStatus (Smsg);
if (Smsg -> sm_Flags & SDMF_SIG_MASK)
{
printf ("Warning: shutdown message timed out.\n");
if (!ExpectTimeout)
ExpectTimeout = 1;
}
if (Smsg -> sm_Flags & SDMF_CTRL_C)
{
/* We didn't receive a timeout yet but a CTRL-C during a
broadcast is unlikely if there was no timeout ahead.
*/
if (!ExpectTimeout)
ExpectTimeout = 1;
}
if (BroadcastTimeout)
{
if (Smsg -> sm_Flags & SDMF_SIG_MASK)
{
RemShutdownPort (Smsg -> sm_Context -> sc_Port);
while (!(Smsg = AllocShutdownMessage ()))
Delay (50); /* Better ideas welcome ... */
}
else
AbortIO ((struct IORequest *) TimerReq);
WaitIO ((struct IORequest *) TimerReq);
SetSignal (0L, TimerMask);
}
if (!point_of_no_return)
{
if (Smsg -> sm_Flags & SDMF_CANCEL)
CancelShutdown ();
}
}
void
AbortableDelay (int seconds)
{
ShutdownMessage *sm;
int abort = 0;
ULONG mask;
TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
TimerReq -> tr_time.tv_secs = seconds;
TimerReq -> tr_time.tv_micro = 0;
SendIO ((struct IORequest *) TimerReq);
while (1)
{
mask = Wait (WaitMask);
if (mask & ShutdownMask)
{
do
WaitPort (ShutdownPort);
while (!(sm = (ShutdownMessage *) GetMsg (ShutdownPort)));
if (sm -> sm_Status == SHUTDOWN_ABORT)
if (point_of_no_return)
sm -> sm_Status = SHUTDOWN_UMOUNT;
else
abort = 1;
ReplyMsg ((struct Message *) sm);
}
if (mask & ReplyMask) /* late reply */
{
if (GetMsg (ReplyPort))
SContext.sc_TimeOuts --;
}
if (mask & SIGBREAKF_MASK || abort)
{
if (point_of_no_return)
{
printf (SorryTooLate);
continue;
}
if (!(mask & TimerMask))
AbortIO ((struct IORequest *) TimerReq);
WaitIO ((struct IORequest *) TimerReq);
SetSignal (0L, TimerMask);
if (mask & SIGBREAKF_CTRL_C || abort)
{
if (mask & SIGBREAKF_CTRL_C && !ExpectTimeout)
printf ("CTRL-C\n");
CancelShutdown ();
printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
}
if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
{
printf ("CTRL-D\n");
return;
}
if (!FastBoot)
{
FastBoot = 1;
if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
{
printf ("CTRL-E\n");
GoDown (0);
}
if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
{
printf ("CTRL-F\n");
GoDown (1);
}
}
else
return;
}
if (mask & TimerMask) /* done waiting */
return;
}
}
int
main (int argc, char *argv[])
{
int cancel_flag = 0, abortable_flag = 1;
int shutdown_time = 10, shutdown_interval;
int opt;
bzero (&SContext, sizeof (ShutdownContext));
NewList (&SContext.sc_List);
SetTaskPri (FindTask (0L), 10);
while ((opt = getopt (argc, argv, "chnrs:t:T:")) != -1)
switch (opt)
{
case 'n': abortable_flag = 0; break;
case 'r': HaltFlag = 0; break;
case 'h': HaltFlag = 1; break;
case 't': shutdown_time = atoi (optarg); break;
case 's': SyncTime = atoi (optarg); break;
case 'c': cancel_flag = 1; break;
case 'T': BroadcastTimeout = atoi (optarg); break;
default:
printf ("Usage: %s [-chnr] [-t <time>] [-s <sync time>] [-T <timeout>].\n", argv[0]);
exit (EXIT_FAILURE);
}
if (HaltFlag)
IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
if (!(HaltBase = OpenLibrary ("halt.library", 0)))
CleanUp ("Failed to open halt.library.\n");
if (!(ReplyPort = CreateMsgPort ()))
CleanUp (CantAllocatePort);
ReplyMask = 1 << ReplyPort -> mp_SigBit;
if (!(Smsg = AllocShutdownMessage ()))
CleanUp (OutOfMemory);
if (abortable_flag)
ShutdownFlags = SDMF_ABORTABLE;
/* open timer device */
if (!(TimerPort = CreateMsgPort ()))
CleanUp (CantAllocatePort);
if (!(TimerReq = (struct timerequest *)
CreateIORequest (TimerPort, sizeof (struct timerequest))))
CleanUp (OutOfMemory);
if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
CleanUp ("Can't open timer device.\n");
Smsg -> sm_Context -> sc_Mask = TimerMask = 1 << TimerPort -> mp_SigBit;
if (cancel_flag)
{
Smsg -> sm_Status = SHUTDOWN_ABORT;
if (!PutAndGet (Smsg, ShutdownPortname))
CleanUp ("Shutdown is not running.\n");
if (Smsg -> sm_Status == SHUTDOWN_UMOUNT)
CleanUp (SorryTooLate);
CleanUp (ShutdownCancelled);
}
/* don't start shutdown twice */
Forbid ();
if (FindPort (ShutdownPortname))
{
Permit ();
CleanUp ("Shutdown is already running.\n");
}
Permit ();
if (!(ShutdownPort = CreateMsgPort ()))
CleanUp (CantAllocatePort);
if (!(ShutdownPort -> mp_Node.ln_Name =
AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
CleanUp (OutOfMemory);
bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
ShutdownPort -> mp_Node.ln_Pri = 0;
AddPort (ShutdownPort);
ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
WaitMask = ReplyMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
while (shutdown_time > 5)
{
shutdown_interval = shutdown_time / 2;
printf ("The system is going down in %d seconds.\n", shutdown_time);
Smsg -> sm_Status = SHUTDOWN_WARN;
Smsg -> sm_TimeLeft = shutdown_time;
BroadcastShutdownMsg ();
AbortableDelay (shutdown_interval);
shutdown_time -= shutdown_interval;
}
GoDown (0);
}
int
GoDown (int now)
{
struct EasyStruct es = {
sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
};
if (!now)
{
/* last warning */
Smsg -> sm_Status = SHUTDOWN_NOW;
Smsg -> sm_TimeLeft = 5;
BroadcastShutdownMsg ();
printf ("The system is going down in 5 seconds.\n");
AbortableDelay (5);
/* too late for writing */
Smsg -> sm_Status = SHUTDOWN_UMOUNT;
Smsg -> sm_TimeLeft = 0;
BroadcastShutdownMsg ();
}
point_of_no_return = 1;
ShutdownFlags &= ~SDMF_ABORTABLE;
printf ("The system is going down, unmounting filesystems.\n");
Unmount (NULL);
AbortableDelay (SyncTime);
if (!now) /* all done, who turns off the light? */
{
Smsg -> sm_Status = SHUTDOWN_HALT;
Smsg -> sm_TimeLeft = 0;
BroadcastShutdownMsg ();
}
printf ("The system is halted.\n");
if (IntuitionBase)
BuildEasyRequest (NULL, &es, NULL);
Delay (10); /* wait 0.5 seconds */
Reboot (HaltFlag); /* 0 = reboot, 1 = halt */
}